/*
 * @Author: 杰编程 2306248989@qq.com
 * @Date: 2023-08-03 19:56:16
 * @LastEditors: 杰编程 2306248989@qq.com
 * @LastEditTime: 2023-08-04 15:51:25
 * @FilePath: /lesson23/udp/udp_server.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <string>
#include<functional>
#include<unordered_map>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <cstring>
#include <cerrno>

#include "errno.hpp"
#include"lockGuard.hpp"
#include"thread.hpp"
#include"ringQueue.hpp"

namespace ns_server
{
    using func_t = std::function<std::string(std::string)>;
    static const u_int16_t default_port = 8686;
    class UdpServer
    {
    public:
        UdpServer(u_int16_t port = default_port)
            : _port(port)
        {
            pthread_mutex_init(&_mutex,nullptr);
            p=new thread(1,std::bind(&UdpServer::Recv,this));
            c=new thread(2,std::bind(&UdpServer::Broadcast,this));
        }

        void Start()
        {
            // 1. 创建socket接口，打开网络文件
            _sock = socket(AF_INET, SOCK_DGRAM, 0);
            if (_sock < 0)
            {
                perror("socket error:");
                exit(SOCKET_ERR);
            }
            std::cout << "create socket successful:" << _sock << std::endl;

            // 2. 给服务器指明IP地址和端口号
            // 2.1 初始化本地变量
            struct sockaddr_in local;
            memset(&local, 0, sizeof(sockaddr_in));
            local.sin_family = AF_INET;         // 地址类型，初始化为IPv4
            local.sin_port = htons(_port);      // 端口号
            local.sin_addr.s_addr = INADDR_ANY; // IP地址
            // 2.2 将本地变量绑定到socket文件中
            int ret = bind(_sock, reinterpret_cast<struct sockaddr *>(&local), sizeof(local));
            if (ret != 0)
            {
                perror("bind error: ");
                exit(BIND_ERR);
            }
            std::cout << "bind socket successful: "<< _sock << std::endl;

            // 3. 运行多线程
            p->run();
            c->run();
        }

        // void Start()
        // {
        //     char buffer[1024]={0};
        //     while(true)
        //     {
        //         //1. 接受数据
        //         struct sockaddr_in peer;
        //         memset(&peer,0,sizeof(peer));
        //         socklen_t addrlen=sizeof(peer);
        //         ssize_t n=recvfrom(_sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&addrlen);
        //         if(n>0)buffer[n]='\0';
        //         else continue;
        //
        //         //2. 处理数据
        //         //2.1 提取客户端信息
        //         std::string clientIP=inet_ntoa(peer.sin_addr);
        //         uint16_t clinentPort=ntohs(peer.sin_port);
        //         // //2.2 echo服务器，直接进行信息打印
        //         // std::cout<<clientIP<<"-"<<clinentPort<<" :"<<buffer<<std::endl;
        //         // 2.2 数据进行任务处理
        //         std::string str=_fun(buffer);
        //        
        //         //3. 发送数据
        //         sendto(_sock,str.c_str(),str.size(),0,reinterpret_cast<struct sockaddr*>(&peer),addrlen);
        //     }
        // }
        
        void AddClinet(const std::string& str, const struct sockaddr_in& peer)
        {
            auto pos=_clients.find(str);
            if(pos!=_clients.end())return;
            LockGuard lockguard(&_mutex);
            _clients.insert(std::make_pair(str,peer));
        }

        void Recv()
        {
            char buffer[1024]={0};
            while(true)
            {
                //1. 接受数据
                struct sockaddr_in peer;
                memset(&peer,0,sizeof(peer));
                socklen_t addrlen=sizeof(peer);
                ssize_t n=recvfrom(_sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&addrlen);
                if(n>0)buffer[n]='\0';
                else continue;

                //2. 处理数据
                //2.1 保存数据
                {
                    LockGuard lockguard(&_mutex);
                    _rq.push(buffer);
                    std::cout<<pthread_self()<<":保存数据:"<<buffer<<std::endl;
                }
                //2.2 提取客户端信息,并添加用户信息
                std::string clientIP=inet_ntoa(peer.sin_addr);
                uint16_t clinentPort=ntohs(peer.sin_port);
                std::string str=clientIP+std::to_string('-')+std::to_string(clinentPort);
                AddClinet(str,peer);
            }
        }
        void Broadcast()
        {
            while(true)
            {
                std::string sending;
                {
                    LockGuard lockguard(&_mutex);
                    _rq.pop(&sending);
                }

                std::vector<struct sockaddr_in> v;
                for(const auto& e:_clients)
                {
                    std::cout<<e.first<<"will get:"<<sending.c_str()<<std::endl;
                    v.push_back(e.second);
                }

                for(auto user:v)
                {
                    
                    sendto(_sock,sending.c_str(),sending.size(),0,(struct sockaddr*)&user,sizeof(user));
                }
                std::cout<<sending.c_str()<<" :: sending done ..."<<std::endl;
            }
        }
        ~UdpServer() 
        {
            pthread_mutex_destroy(&_mutex);

            p->join();
            c->join();
            delete p;
            delete c;
        }

    private:
        int _sock;
        uint16_t _port;

        func_t _fun;
        RingQueue<std::string> _rq;
        std::unordered_map<std::string,struct sockaddr_in> _clients;
        pthread_mutex_t _mutex;
        thread* p;
        thread* c;
    };
}
